Getting and analyzing remotely sensed open data#

2023.05.16, 2023.05.23

Our last tutorial will show you how to navigate through a STAC catalog, search within a cloud-hosted data set, and acquire some popular open satellite data sets.

Goals#

  1. Use Intake-STAC to browse a STAC catalog and load the data

  2. TBD - Make a video showing the time lapse of the Taoyuan international airport?

Installation#

We will use Intake, an interface for loading data into the scientific Python ecosystem. Here we install intake-stac, an intake-based library for loading STAC catalogs. (Intake itself will be installed along with this library because of the dependency.) In addtion to that, we will need hvplot again to visualize our data.

!pip install intake-stac hvplot

Goal 1 procedure#

Let’s import the necessary modules:

import intake
import hvplot.xarray

STAC#

STAC logo by the STAC team, CC-BY 4.0.

SpatioTemporal Asset Catalogs (STAC) are a set of specification for describing spatialtemporal data sets, such as satellite images and spatial vector data. Satellite data sets described by the language of STAC can be more accessible because users will not spend time learning how to search and access data again and again (which is typical for the current commercial data sets). The first version of STAC was released in May 2021 and became popular within major satellite data providers. You can also check out this blogpost by the Planet Inc. for more details.

The full specification of STAC as well as numerous tutorials are available on the STAC website. Also, on the STAC intex website you can find a collection of STAC catalogs to explore.

Intake#

Description about Intake. PySTAC and Intake.

The Planet disaster data#

In this tutorial, we will use the Planet disaster data, a small data set that Planet Inc. prepared for showing how STAC works with the data analysis workflow. We will be looking at Hurricane Harvey, one of the most devastating natural disasters in the U.S. history. In this tutorial, we will get the data acquired by the PlanetScope satellite constellation over Houston, TX, U.S. on August 31, 2017, a few days after the hurricane brought the record-breaking rainfall.

catalog_url = 'https://www.planet.com/data/stac/catalog.json'

STAC browser#

The STAC brower provides an easy way to visualize a STAC catalog.

Workflow#

Now we use Intake to open the STAC cataog:

catalog = intake.open_stac_catalog(catalog_url)
catalog
planet:
  args:
    stac_obj: https://www.planet.com/data/stac/catalog.json
  description: ''
  driver: intake_stac.catalog.StacCatalog
  metadata:
    description: This catalog serves as the main root STAC Catalog for Planet Labs.
      It links to 4 small static catalogs of open data, including a small set of Planet
      Disaster Data, some CC-BY SkySat collects and the complete Spacenet 7 images
      and labels.
    id: planet
    stac_extensions:
    - https://stac-extensions.github.io/stats/v0.2.0/schema.json
    stac_version: 1.0.0
    stats:catalogs:
      count: 9
      versions:
        1.0.0: 9
    stats:collections:
      count: 7
      versions:
        1.0.0: 7
    stats:items:
      assets:
        application/geo+json: 1423
        application/json: 26
        image/jpeg: 1
        image/png: 13
        image/tiff: 2
        image/tiff; application=geotiff: 2253
        image/tiff; application=geotiff; profile=cloud-optimized: 425
        text/xml: 3
      count: 3708
      extensions:
        https://stac-extensions.github.io/eo/v1.0.0/schema.json: 396
        https://stac-extensions.github.io/label/v1.0.0/schema.json: 1423
        https://stac-extensions.github.io/projection/v1.0.0/schema.json: 385
        https://stac-extensions.github.io/raster/v1.0.0/schema.json: 3
        https://stac-extensions.github.io/raster/v1.1.0/schema.json: 371
        https://stac-extensions.github.io/view/v1.0.0/schema.json: 31
      versions:
        1.0.0: 3708
    title: Planet Root STAC Catalog
    type: Catalog
list(catalog)
['planet-stac-skysat',
 'planet-disaster-data',
 'sn7',
 'planet/fusion/14N/29E-188N',
 'education']
collection = catalog['planet-disaster-data']
collection
planet-disaster-data:
  args:
    stac_obj: https://www.planet.com/data/stac/disasters/collection.json
  description: '[Planet Disaster Data](https://www.planet.com/disasterdata/) makes
    imagery available directly to the public, volunteers, humanitarian organizations,
    and other coordinating bodies in support of the International Charter for Space
    and Major Disasters. Data is released for individual disaster events, providing
    a 30 day window pre- and post-disaster. Imagery is provided under Creative Commons
    licenses, free of charge, with either CC-BY-SA or CC-BY-NC. This STAC catalog
    provides fully public access of a very small subset of the imagery, as a proof
    of concept.'
  driver: intake_stac.catalog.StacCollection
  metadata:
    catalog_dir: ''
collection.metadata
{'type': 'Collection',
 'id': 'planet-disaster-data',
 'stac_version': '1.0.0',
 'description': '[Planet Disaster Data](https://www.planet.com/disasterdata/) makes imagery available directly to the public, volunteers, humanitarian organizations, and other coordinating bodies in support of the International Charter for Space and Major Disasters. Data is released for individual disaster events, providing a 30 day window pre- and post-disaster. Imagery is provided under Creative Commons licenses, free of charge, with either CC-BY-SA or CC-BY-NC. This STAC catalog provides fully public access of a very small subset of the imagery, as a proof of concept.',
 'stac_extensions': [],
 'title': 'Planet Disaster Data',
 'keywords': ['disaster', 'open'],
 'summaries': {'platform': ['SS02', 'SSC1', '101c'],
  'constellation': ['skysat', 'planetscope'],
  'eo:cloud_cover': {'minimum': 0, 'maximum': 24},
  'eo:gsd': {'minimum': 0.9, 'maximum': 3.7},
  'view:off_nadir': {'minimum': 0.2, 'maximum': 27.3},
  'view:sun_azimuth': {'minimum': 122, 'maximum': 231.9},
  'view:sun_elevation': {'minimum': 56.3, 'maximum': 65.1}},
 'providers': [{'name': 'Planet',
   'description': 'Contact Planet at https://www.planet.com/contact-sales/',
   'roles': ['producer', 'processor'],
   'url': 'https://www.planet.com'},
  {'name': 'Planet Disaster Team <disaster-team@planet.com>',
   'description': 'The Planet Disaster Data Team has released this data as CC-BY-SA-4.0 to help disaster response',
   'roles': ['licensor'],
   'url': 'https://www.planet.com/disasterdata/'},
  {'name': 'Google Cloud Platform',
   'description': 'Hosting is done on a GCP storage bucket owned by the Planet Disaster Data team',
   'roles': ['host'],
   'url': 'https://storage.googleapis.com/pdd-stac/'}],
 'extent': {'spatial': {'bbox': [[-96, 28, -93, 31]]},
  'temporal': {'interval': [['2017-08-28T10:00:00Z', None]]}},
 'license': 'CC-BY-SA-4.0'}
item = collection['hurricane-harvey']['hurricane-harvey-0831']['Houston-East-20170831-103f-100d-0f4f-RGB']
item
mosaic:
  args:
    chunks: {}
    urlpath: https://storage.googleapis.com/pdd-stac/disasters/hurricane-harvey/0831/Houston-East-20170831-103f-100d-0f4f-3-band.tif
  description: 3 Band RGB Mosaic
  direct_access: allow
  driver: intake_xarray.raster.RasterIOSource
  metadata:
    href: https://storage.googleapis.com/pdd-stac/disasters/hurricane-harvey/0831/Houston-East-20170831-103f-100d-0f4f-3-band.tif
    plots:
      geotiff:
        cmap: viridis
        data_aspect: 1
        dynamic: true
        frame_width: 500
        kind: image
        rasterize: true
        x: x
        y: y
    roles:
    - data
    title: 3 Band RGB Mosaic
    type: image/tiff; application=geotiff; profile=cloud-optimized
thumbnail:
  args:
    chunks: {}
    urlpath: https://storage.googleapis.com/pdd-stac/disasters/hurricane-harvey/0831/Houston-East-20170831-103f-100d-0f4f-3-band.png
  description: Thumbnail
  direct_access: allow
  driver: intake_xarray.image.ImageSource
  metadata:
    href: https://storage.googleapis.com/pdd-stac/disasters/hurricane-harvey/0831/Houston-East-20170831-103f-100d-0f4f-3-band.png
    plots:
      thumbnail:
        bands: channel
        data_aspect: 1
        flip_yaxis: true
        kind: rgb
        x: x
        xaxis: false
        y: y
        yaxis: false
    roles:
    - thumbnail
    title: Thumbnail
    type: image/png
thumbnail = item['thumbnail']
# make a note for type(thumbnail)
thumbnail.urlpath
'https://storage.googleapis.com/pdd-stac/disasters/hurricane-harvey/0831/Houston-East-20170831-103f-100d-0f4f-3-band.png'
da_thumbnail = thumbnail.to_dask()
da_thumbnail
<xarray.DataArray (y: 552, x: 549, channel: 3)>
dask.array<xarray-<this-array>, shape=(552, 549, 3), dtype=uint8, chunksize=(552, 549, 3), chunktype=numpy.ndarray>
Coordinates:
  * y        (y) int64 0 1 2 3 4 5 6 7 8 ... 543 544 545 546 547 548 549 550 551
  * x        (x) int64 0 1 2 3 4 5 6 7 8 ... 540 541 542 543 544 545 546 547 548
  * channel  (channel) int64 0 1 2
da_thumbnail.hvplot.image(x='x', y='y', data_aspect=1)
mosaic = item['mosaic']
da_mosaic = mosaic.to_dask()
da_mosaic
<xarray.DataArray (band: 3, y: 22094, x: 21984)>
dask.array<open_rasterio-501c37a1d96e315c20253204d9aec1ce<this-array>, shape=(3, 22094, 21984), dtype=uint8, chunksize=(3, 22094, 21984), chunktype=numpy.ndarray>
Coordinates:
  * band     (band) int64 1 2 3
  * y        (y) float64 3.524e+06 3.524e+06 3.524e+06 ... 3.447e+06 3.447e+06
  * x        (x) float64 -1.066e+07 -1.066e+07 ... -1.058e+07 -1.058e+07
Attributes: (12/13)
    transform:               (3.4638558402435815, 0.0, -10657435.586420376, 0...
    crs:                     +init=epsg:3857
    res:                     (3.4638558402435815, 3.4638558402435815)
    is_tiled:                1
    nodatavals:              (nan, nan, nan)
    scales:                  (1.0, 1.0, 1.0)
    ...                      ...
    AREA_OR_POINT:           Area
    TIFFTAG_DATETIME:        2017:09:01 15:10:49
    TIFFTAG_RESOLUTIONUNIT:  2 (pixels/inch)
    TIFFTAG_SOFTWARE:        Adobe Photoshop CC 2015.5 (Macintosh)
    TIFFTAG_XRESOLUTION:     72
    TIFFTAG_YRESOLUTION:     72
da_mosaic_subset = da_mosaic.sel(x=slice(-10641000, -10638000), y=slice(3474000, 3471000))
da_mosaic_subset.hvplot.rgb(x='x', y='y', data_aspect=1)